package com.zlop.config;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.zlop.common.exception.BaseException;
import com.zlop.common.response.CodeEnum;
import com.zlop.common.response.RestfulResponse;

/**
 * 系统配置
 *
 * @author	曾令鹏
 * @since	1.0
 * @version 2018年5月8日 曾令鹏
 */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
	
	/** 日志处理类 */
	Logger logger = LoggerFactory.getLogger(WebConfig.class);
	
	private static String applicationName;
	
	@Bean
    public HttpMessageConverter<String> responseBodyConverter() {
        StringHttpMessageConverter converter = new StringHttpMessageConverter(
                Charset.forName("UTF-8"));
        return converter;
    }
	
	/**
	 * Json转换使用FastJson
	 */
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
		FastJsonConfig config = new FastJsonConfig();
		config.setSerializerFeatures(SerializerFeature.BrowserCompatible, // 数字字符串化
				SerializerFeature.WriteMapNullValue, 	  // 保留空的字段
				SerializerFeature.WriteNullStringAsEmpty, // String null -> ""
				SerializerFeature.WriteNullNumberAsZero); // Number null -> 0
		config.setDateFormat("yyyy-MM-dd HH:mm");
		converter.setFastJsonConfig(config);
		converter.setDefaultCharset(Charset.forName("UTF-8"));
		converters.add(converter);
	}
	
	/**
	 * 统一异常处理
	 */
	@Override
	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
		exceptionResolvers.add(new HandlerExceptionResolver() {
			public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
					Object handler, Exception e) {
				RestfulResponse<Void> restfulResponse = null;
				if (e instanceof IllegalArgumentException) {
					restfulResponse = RestfulResponse.build(CodeEnum.ILLEGAL_ARGUMENT_ERROR, e.getMessage());
				} else if (e instanceof NoHandlerFoundException) {
					restfulResponse = RestfulResponse.build(CodeEnum.MALFORMEDURL, "接口 [" + request.getRequestURI() + "] 不存在");
				} else if (e instanceof BaseException) {
					BaseException baseException = (BaseException) e;
					String message = String.format("应用 :%s 出现 [%s]，请求参数%s，异常摘要：%s", baseException.getApp(), baseException.getMessage(), 
							Arrays.toString(baseException.getArgs()),
							baseException.getMessage());
					logger.error(message, e);
					restfulResponse = RestfulResponse.build(CodeEnum.OTHER_ERROR, e.getMessage());
				} else if (e instanceof ServletException) {
					restfulResponse = RestfulResponse.build(CodeEnum.OTHER_ERROR, e.getMessage());
				} else {
					restfulResponse = RestfulResponse.build(CodeEnum.OTHER_ERROR, "接口 [" + request.getRequestURI() + "] 出现错误,请联系管理员");
					
					String message = null;
					if (handler instanceof HandlerMethod) {
						HandlerMethod handlerMethod = (HandlerMethod) handler;
						message = String.format("接口 :[%s] 出现异常,方法:%s.%s，异常摘要,%s", request.getRequestURI(),
								handlerMethod.getBean().getClass().getName(), handlerMethod.getMethod().getName(),
								e.getMessage());
					} else {
						message = e.getMessage();
					}
					logger.error(message, e);
				}
				responseResult(response, restfulResponse);
				return new ModelAndView();
			}
		});
	}
	
	/**
	 * 跨域
	 */
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**").allowedOrigins("*").allowCredentials(true)
				.allowedMethods("GET", "POST", "DELETE", "PUT").maxAge(3600);
	}
	
	/**
	 * 写入响应结果
	 * 
	 * @param response 响应对象
	 * @param restfulResponse 接口返回结果
	 */
	private void responseResult(HttpServletResponse response, RestfulResponse<Void> restfulResponse) {
		response.setCharacterEncoding("UTF-8");
		response.setHeader("Content-type", "application/json;charset=UTF-8");
		response.setStatus(200);
		PrintWriter writer = null;
		try {
			writer = response.getWriter();
			writer.write(JSON.toJSONString(restfulResponse));
			writer.flush();
		} catch (IOException ex) {
			logger.error(ex.getMessage());
		} finally {
			if(writer != null){
				writer.close();
			}
		}
	}
	
	
	/**
     * @param applicationName 设置 applicationName 属性值为参数值 applicationName
     */
	@Value("${app.application.name:}")
	public void setApplicationName(String applicationName) {
		WebConfig.applicationName = applicationName;
	}
	
	/**
     * @return 获取 applicationName属性值
     */
	public static String getApplicationName() {
		return WebConfig.applicationName;
	}

}
